package com.zzzn.rhtx.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.zzzn.rhtx.entity.*;
import com.zzzn.rhtx.service.CallingStartEndService;
import com.zzzn.rhtx.service.RhtxClient;
import jdk.nashorn.internal.ir.annotations.Ignore;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @auther Yuzhong.Guo
 * @date 2022/11/7 15:54
 */
@Slf4j
@Service
public class CallingStartEndServiceImpl implements CallingStartEndService {

    @Autowired
    private RhtxClient rhtxClient;

    public volatile AtomicReference<Object> rtspUrlAto = new AtomicReference<>();
    public volatile AtomicReference<Object> meetIdAto = new AtomicReference<>();

    public ConcurrentHashMap<String, OneToMoreCallRequestDTO> requestDTOConcurrentHashMap = new ConcurrentHashMap<>();

    /**
     * 开始1对多  语音   视频
     * 1.创建会议
     * 2.选呼
     * 3.调用两次视频会商
     * @param requestDo
     * @return
     */
    @Override
    public CallMoreResultVo startPollCall(OneToMoreCallRequestDTO requestDo) {
        //1.创建会议
        CreateMeetingRequestDo createMeetingRequestDo = CreateMeetingRequestDo.builder().request(CreateMeetingRequestDo.CreateMeeting.builder()
                .id("100000")
                .type("CreateMeet")
                .meetName(requestDo.getMeetName())
                .meetNum(requestDo.getMeetNum())
                .isAllowSpeak(requestDo.getIsAllowSpeak())
                .meetMode(requestDo.getMeetMode())
                .callinState(requestDo.getCallinState())
                .callinNum(requestDo.getCallinNum()).callinPwd(requestDo.getCallinPwd()).build()).build();
        MakeCallResponse createMeetResult = rhtxClient.createMeet(createMeetingRequestDo);
        if (ObjectUtils.isEmpty(createMeetResult) || createMeetResult.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new CallMoreResultVo();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log.error("#createMeet.sleep.error:", e);
        }
        //2.调用poll接口，获取到创建会议接口发回调结果。主要是为了拿meetID、rtspUrl
        MakeCallPollResponse firstPollResult = rhtxClient.poll();
        if (!checkPollResult(firstPollResult)) {
            return new CallMoreResultVo();
        }
        firstPollResult.getMsg().forEach(o -> {
            if (o instanceof Map) {
                if (Objects.equals(((Map<?, ?>) o).get("event"), "NewMeet") && Objects.equals(((Map<?, ?>) o).get("meetName"), requestDo.getMeetName())) {
                    if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("rtspUrl"))) {
                        rtspUrlAto.set(((Map<?, ?>) o).get("rtspUrl"));
                    }
                    if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("meetID"))) {
                        meetIdAto.set(((Map<?, ?>) o).get("meetID"));
                    }
                }

            }
        });

        //3.选呼，意思就是拉人入会
        log.info("createMeet meetID:{}", meetIdAto.get());
        if (ObjectUtils.isEmpty(meetIdAto.get())) {
            return new CallMoreResultVo();
        }
        SelectCallRequestDo selectCallRequestDo = new SelectCallRequestDo();
        SelectCallRequestDo.SelectCallRequest selectCallRequest = new SelectCallRequestDo.SelectCallRequest();
        selectCallRequest.setId("100000");
        selectCallRequest.setType("SelectCall");
        selectCallRequest.setCallingDevice(requestDo.getCallingDevice());
        selectCallRequest.setCallMode("parallel");
        selectCallRequest.setMeetID(meetIdAto.get() + "");
        selectCallRequest.setCalled(requestDo.getCalled());
        selectCallRequestDo.setRequest(selectCallRequest);
        MakeCallResponse selectCallResponse = rhtxClient.selectCall(selectCallRequestDo);
        if (ObjectUtils.isEmpty(selectCallResponse) || selectCallResponse.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new CallMoreResultVo();
        }
        requestDTOConcurrentHashMap.put("startPollCall", requestDo);
        //4.调用两次视频会商
        return setMeetVideoMixAndPollRtn(meetIdAto.get() + "", requestDo, rtspUrlAto);
    }

    /**
     * 调用两次视频会商
     * 调用poll返回
     * @return
     */
    private CallMoreResultVo setMeetVideoMixAndPollRtn(String meetId, OneToMoreCallRequestDTO requestDo, AtomicReference<Object> rtspUrlAto) {
        //4.调用两次视频会商
        SetMeetVideoMixRequestDo setMeetVideoMixRequestDo = convertSetMeetVideoMixRequestDo(meetId, requestDo);
        MakeCallResponse firstSetMeetVideoMixResp = rhtxClient.setMeetVideoMix(setMeetVideoMixRequestDo);
        if (ObjectUtils.isEmpty(firstSetMeetVideoMixResp) || firstSetMeetVideoMixResp.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new CallMoreResultVo();
        }
        MakeCallResponse secondSetMeetVideoMixResp = rhtxClient.setMeetVideoMix(setMeetVideoMixRequestDo);
        if (ObjectUtils.isEmpty(secondSetMeetVideoMixResp) || secondSetMeetVideoMixResp.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new CallMoreResultVo();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log.error("#setMeetVideoMix.sleep.error:", e);
        }
        //5.调用poll接口拉取最终数据返回
        MakeCallPollResponse secondPollResult = rhtxClient.poll();
        if (!checkPollResult(secondPollResult)) {
            return new CallMoreResultVo();
        }
        CallMoreResultVo finalResponse = new CallMoreResultVo();
        finalResponse.setStatus(secondPollResult.getStatus());
        CallMoreResultVo.CallMoreResult moreResult = new CallMoreResultVo.CallMoreResult();
        if ("video".equals(requestDo.getMeetMode()) && !ObjectUtils.isEmpty(rtspUrlAto.get())) {
            moreResult.setRtspUrl(rtspUrlAto.get() + "");
        }
        secondPollResult.getMsg().forEach(o -> {
            if (o instanceof Map) {
                if (Objects.equals(((Map<?, ?>) o).get("event"), "ModMeet")
                        && Objects.equals(((Map<?, ?>) o).get("meetName"), requestDo.getMeetName())
                        && Objects.equals(((Map<?, ?>) o).get("meetID"), meetId)
                        && Objects.equals(((Map<?, ?>) o).get("mixType"), setMeetVideoMixRequestDo.getRequest().getMixType())) {
                    int mixType = Integer.parseInt(((Map<?, ?>) o).get("mixType") + "");
                    if (mixType != 1) {
                        moreResult.setStatus("succ");
                        moreResult.setMixType(((Map<?, ?>) o).get("mixType") + "");
                    }
                }
            }
        });
        finalResponse.setResult(moreResult);
        return finalResponse;
    }

    /**
     * 加入会议分为两步
     * 1.加入会议
     * 2.调用两次视频会商
     * @param joinMeetDTO
     * @return
     */
    @Override
    public CallMoreResultVo joinMeetCall(JoinMeetDTO joinMeetDTO) {
        //1.加入会议
        JoinMeetCallRequestDo requestDo = JoinMeetCallRequestDo.builder().request(JoinMeetCallRequestDo.JoinMeetCall.builder()
                .id("100000")
                .type("JoinMeetCall")
                .callingDevice(joinMeetDTO.getCallingDevice())
                .called(joinMeetDTO.getCalled()).meetID(meetIdAto.get() + "").build()).build();
        BaseResult joinMeetCallResp = rhtxClient.joinMeetCall(requestDo);
        if (ObjectUtils.isEmpty(joinMeetCallResp) || joinMeetCallResp.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new CallMoreResultVo();
        }
        OneToMoreCallRequestDTO oneToMoreCallRequestDTO = requestDTOConcurrentHashMap.get("startPollCall");
        oneToMoreCallRequestDTO.getCalled().add(joinMeetDTO.getCalled());
        return setMeetVideoMixAndPollRtn(meetIdAto.get() + "", oneToMoreCallRequestDTO, rtspUrlAto);
    }

    /**
     * 组织两次调用视频会商接口请求数据
     */
    private SetMeetVideoMixRequestDo convertSetMeetVideoMixRequestDo(String meetId, OneToMoreCallRequestDTO requestDo) {
        SetMeetVideoMixRequestDo setMeetVideoMixRequestDo = new SetMeetVideoMixRequestDo();
        SetMeetVideoMixRequestDo.SetMeetVideoMixRequest setMeetVideoMixRequest = new SetMeetVideoMixRequestDo.SetMeetVideoMixRequest();
        setMeetVideoMixRequest.setId("10000");
        setMeetVideoMixRequest.setType("SetMeetVideoMix");
        setMeetVideoMixRequest.setMeetID(meetId);
        setMeetVideoMixRequest.setVideoType("720P");
        MakeCallRequestDo.MakeCall.Called called = new MakeCallRequestDo.MakeCall.Called();
        called.setCalledDevice(requestDo.getCallingDevice());
        List<MakeCallRequestDo.MakeCall.Called> source = requestDo.getCalled();
        source.add(called);
        setMeetVideoMixRequest.setSource(source);
        setMeetVideoMixRequest.setMixType(source.size() + "");

        setMeetVideoMixRequestDo.setRequest(setMeetVideoMixRequest);
        return setMeetVideoMixRequestDo;
    }


    /**
     * 获取分屏数
     * @param count
     * @return
     */
    private String getMixType(int count) {
        //会商输出几分屏，目前支持：1，2，4，6，8，9，13，16
        int mixType = 4;
        if (count <= 4) {
        } else if (count <= 6) {
            mixType = 6;
        } else if (count <= 8) {
            mixType = 8;
        } else if (count <= 9) {
            mixType = 9;
        } else if (count <= 13) {
            mixType = 13;
        } else if (count <= 16) {
            mixType = 16;
        }
        return mixType + "";
    }

    /**
     * 检查poll轮询获取消息接口是否返回数据正常
     * @param pollResponse
     * @return
     */
    private boolean checkPollResult(MakeCallPollResponse pollResponse) {
       if (!ObjectUtils.isEmpty(pollResponse)
               && pollResponse.getStatus() == RhtxClient.SUCCESS_STATUS
               && !CollectionUtils.isEmpty(pollResponse.getMsg())) {
           return true;
       }
       return false;
    }

    /**
     * 结束1对多
     * 1.先会议踢出所有人
     * 2.结束会议
     * @return
     */
    @Override
    public BaseResult endMoreCall() {
        //1.会议踢出所有人
        MeetingSpeakRequestDo meetingSpeakRequestDo = MeetingSpeakRequestDo.builder()
                .request(MeetingSpeakRequestDo.MeetingSpeak.builder()
                        .id("100000")
                        .type("MeetKick")
                        .meetID(meetIdAto.get() + "").build()).build();
        BaseResult meetKickRes = rhtxClient.meetKick(meetingSpeakRequestDo);
        if (ObjectUtils.isEmpty(meetKickRes) || meetKickRes.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new BaseResult();
        }
        //2.结束会议
        EndMeetingRequestDo endMeetingRequestDo = EndMeetingRequestDo.builder()
                .request(EndMeetingRequestDo.EndMeeting.builder()
                        .id("100000")
                        .type("EndMeet")
                        .meetID(meetIdAto.get() + "").build()).build();
        BaseResult endMeetRes = rhtxClient.endMeet(endMeetingRequestDo);
        if (ObjectUtils.isEmpty(endMeetRes) || endMeetRes.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new BaseResult();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log.error("#endMeet.error:", e);
        }

        //轮询获取结束会议信息
        MakeCallPollResponse pollResponse = rhtxClient.poll();
        if (ObjectUtils.isEmpty(pollResponse) || pollResponse.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new BaseResult();
        }
        endMeetRes.setStatus(pollResponse.getStatus());
        if (!ObjectUtils.isEmpty(pollResponse)
                && pollResponse.getStatus() == RhtxClient.SUCCESS_STATUS
                && !CollectionUtils.isEmpty(pollResponse.getMsg())) {
            pollResponse.getMsg().forEach(o -> {
                if (o instanceof Map) {
                    if (Objects.equals(((Map<?, ?>) o).get("type"), "EndMeet")) {
                        if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("result"))) {
                            endMeetRes.setMsg(((Map<?, ?>) o).get("result") + "");
                        }
                    }
                }
            });
        }

        requestDTOConcurrentHashMap.clear();
        rtspUrlAto = new AtomicReference<>();
        meetIdAto = new AtomicReference<>();
        return endMeetRes;
    }

    /**
     * 单呼  1对1 语音  视频
     * 语音：单呼 poll
     * 视频：单呼 获取视频通话图像 poll
     * @param requestDo
     * @return
     */
    @Override
    public CallOneResultVo makeCall(OneToOneCallRequestDTO requestDo) {
        if (ObjectUtils.isEmpty(requestDo)) {
            CallOneResultVo callOneResultVo = new CallOneResultVo();
            callOneResultVo.setStatus(0);
            CallOneResultVo.CallOneResult result = new CallOneResultVo.CallOneResult();
            result.setStatus("不能传参为空");
            callOneResultVo.setResult(result);
            return callOneResultVo;
        }
        if (StringUtils.isEmpty(requestDo.getCallingDevice())) {
            CallOneResultVo callOneResultVo = new CallOneResultVo();
            callOneResultVo.setStatus(0);
            CallOneResultVo.CallOneResult result = new CallOneResultVo.CallOneResult();
            result.setStatus("主叫电话号码不能为空");
            callOneResultVo.setResult(result);
            return callOneResultVo;
        }
        if (ObjectUtils.isEmpty(requestDo.getCalled()) || StringUtils.isEmpty(requestDo.getCalled().getCalledDevice())) {
            CallOneResultVo callOneResultVo = new CallOneResultVo();
            callOneResultVo.setStatus(0);
            CallOneResultVo.CallOneResult result = new CallOneResultVo.CallOneResult();
            result.setStatus("被叫电话号码不能为空");
            callOneResultVo.setResult(result);
            return callOneResultVo;
        }
        if (StringUtils.isEmpty(requestDo.getCallType())) {
            //默认语音呼叫
            requestDo.setCallType("audio");
        }
        //1.调用单呼接口
        MakeCallResponse makeCallResponse = rhtxClient.makeCall(MakeCallRequestDo.builder()
                .request(MakeCallRequestDo.MakeCall.builder()
                        .id("100000")
                        .type("MakeCall")
                        .callingDevice(requestDo.getCallingDevice())
                        .called(requestDo.getCalled())
                        .callType(requestDo.getCallType())
                        .duplexMode("full").build()).build());
        if (ObjectUtils.isEmpty(makeCallResponse) || makeCallResponse.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new CallOneResultVo();
        }
        CallOneResultVo finalResponse = new CallOneResultVo();
        CallOneResultVo.CallOneResult oneResult = new CallOneResultVo.CallOneResult();
        //2.如果是语音，直接调用poll返回当前通话状态
        if ("audio".equals(requestDo.getCallType())) {
            log.info("1to1.audio <<<<<<start");
            //调用poll接口拉取数据
            poll(finalResponse, "MakeCall", oneResult);
            log.info("1to1.audio <<<<<<end");
        //3.如果是音视频的，需要先调用获取视频通话图像接口，再去调用poll返回当前通话状态
        } else if ("video".equals(requestDo.getCallType())){
            log.info("1to1.video <<<<<<start");
            String type = "GetVideoRtspUrl";
            GetVideoRtspUrlRequestDo getVideoRtspUrlRequestDo = new GetVideoRtspUrlRequestDo();
            GetVideoRtspUrlRequestDo.GetVideoRtspUrlRequest request = new GetVideoRtspUrlRequestDo.GetVideoRtspUrlRequest();
            request.setId("100000");
            request.setType(type);
            request.setCalledDevice(requestDo.getCalled().getCalledDevice());
            getVideoRtspUrlRequestDo.setRequest(request);
            //获取视频通话图像
            MakeCallResponse videoRtspUrlResponse = rhtxClient.getVideoRtspUrl(getVideoRtspUrlRequestDo);
            if (ObjectUtils.isEmpty(videoRtspUrlResponse) || videoRtspUrlResponse.getStatus() != RhtxClient.SUCCESS_STATUS) {
                return new CallOneResultVo();
            }
            //调用poll接口拉取数据
            poll(finalResponse, type, oneResult);
            log.info("1to1.video <<<<<<end");
        }
        return finalResponse;
    }

    /**
     * 单呼挂断
     * @return
     */
    @Override
    public BaseResult clearCall() {
        BaseResult baseResult = rhtxClient.clearCall();
        if (ObjectUtils.isEmpty(baseResult) || baseResult.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new BaseResult();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log.error("clearCall.thread.error:", e);
        }
        MakeCallPollResponse pollResponse = rhtxClient.poll();
        if (ObjectUtils.isEmpty(pollResponse) || pollResponse.getStatus() != RhtxClient.SUCCESS_STATUS) {
            return new BaseResult();
        }
        baseResult.setStatus(pollResponse.getStatus());
        if (!ObjectUtils.isEmpty(pollResponse)
                && pollResponse.getStatus() == RhtxClient.SUCCESS_STATUS
                && !CollectionUtils.isEmpty(pollResponse.getMsg())) {
            pollResponse.getMsg().forEach(o -> {
                if (o instanceof Map) {
                    if (Objects.equals(((Map<?, ?>) o).get("type"), "ClearCall")) {
                        if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("result"))) {
                            baseResult.setMsg(((Map<?, ?>) o).get("result") + "");
                        }
                    }
                }
            });
        }
        return baseResult;
    }

    /**
     * 调用轮询拉取数据接口
     * @param finalResponse 最终返回
     * @param type 请求接口类型
     * @param oneResult 返回结果
     */
    private void poll(CallOneResultVo finalResponse, String type, CallOneResultVo.CallOneResult oneResult) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log.error("#makeCall.sleep.error:", e);
        }
        //调用poll接口拉取数据
        MakeCallPollResponse pollResponse = rhtxClient.poll();
        finalResponse.setStatus(pollResponse.getStatus());
        if (!ObjectUtils.isEmpty(pollResponse)
                && pollResponse.getStatus() == RhtxClient.SUCCESS_STATUS
                && !CollectionUtils.isEmpty(pollResponse.getMsg())) {
            pollResponse.getMsg().forEach(o -> {
                if (o instanceof Map) {
                    if (Objects.equals(((Map<?, ?>) o).get("type"), type)) {
                        if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("result"))) {
                            oneResult.setStatus(((Map<?, ?>) o).get("result") + "");
                        }
                        if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("rtsp_url"))) {
                            oneResult.setRtspUrl(((Map<?, ?>) o).get("rtsp_url") + "");
                        }
                        finalResponse.setResult(oneResult);
                    }
                }
            });
        }
    }

//    public static void main(String[] args) {
//        MakeCallPollResponse pollResponse = JSONObject.parseObject("{\n" +
//                "    \"status\": 200,\n" +
//                "    \"count\": 2,\n" +
//                "    \"msg\": [\n" +
//                "        {\n" +
//                "            \"meetName\": \"test2022111401\",\n" +
//                "            \"event\": \"NewMeet\",\n" +
//                "            \"meetID\": \"iDispatch_meet20221114@10.20.132.15\"\n" +
//                "        },\n" +
//                "        {\n" +
//                "            \"meetName\": \"test2022111402\",\n" +
//                "            \"event\": \"NewMeet1111\",\n" +
//                "            \"meetID\": \"iDispatch_meet20221114@10.20.132.15\"\n" +
//                "        }\n" +
//                "    ]\n" +
//                "}", MakeCallPollResponse.class);
//        AtomicReference<Object> rtspUrlAto = new AtomicReference<>();
//        AtomicReference<Object> meetIdAto = new AtomicReference<>();
//        pollResponse.getMsg().forEach(o -> {
//            if (o instanceof Map) {
//                if (Objects.equals(((Map<?, ?>) o).get("event"), "NewMeet") && Objects.equals(((Map<?, ?>) o).get("meetName"), "test2022111401")) {
//                    if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("rtspUrl"))) {
//                        rtspUrlAto.set(((Map<?, ?>) o).get("rtspUrl"));
//                    }
//                    if (!ObjectUtils.isEmpty(((Map<?, ?>) o).get("meetID"))) {
//                        meetIdAto.set(((Map<?, ?>) o).get("meetID"));
//                    }
//                }
//
//            }
//        });
//        System.out.println(meetIdAto.get());
//    }
}
